package Threads.ReentrantReadWriteLock;

import Threads.Utils.log;

import java.util.concurrent.locks.ReentrantReadWriteLock;


//一个线程在持有读锁的时候，不可以再获取写锁，但是在持有写锁的时候，可以继续获取读锁
//jdk还提供一个StampedLock，可提高读读并发
public class ReentrantReadWriteLock_test {
    private static ReentrantReadWriteLock LOCK=new ReentrantReadWriteLock();
    private static ReentrantReadWriteLock.ReadLock readLock=LOCK.readLock();
    private static ReentrantReadWriteLock.WriteLock writeLock=LOCK.writeLock();

    public static void main(String[] args) throws InterruptedException {
        //测试读读可并发
        /*new Thread(()->{
            read();
        }).start();
        new Thread(()->{
            read();
        }).start();
        new Thread(()->{
            read();
        }).start();*/

        //测试读写不可并发

        //这里我设置了先让一个写线程获取锁
        //此时，它下面三个到来的读锁获取锁失败进入阻塞队列，睡眠0.1ms再让一个写线程获取锁，再睡眠0.1秒再让一个读线程获取锁
        //当第一个写线程释放锁后
        //三个读线程将获取锁执行
        //接下来写线程获取锁执行
        //再接下来，写线程释放锁之后，最后一个读线程获取锁执行
        //这个例子，很好的证明了读写锁底层的队列机制，当一个线程释放锁后，如果一个读线程拿到了锁，它会接着唤醒队列中排队的读线程
        //直到遇到了写线程或者队列中没有等待线程

        /*
         */
        new Thread(()->{
            write();
        }).start();
        new Thread(()->{
            read();
        }).start();
        new Thread(()->{
            read();
        }).start();
        new Thread(()->{
            read();
        }).start();
        Thread.sleep(100);
        new Thread(()->{
            write();
        }).start();
        Thread.sleep(100);
        new Thread(()->{
            read();
        }).start();
    }

    public static void read(){
        readLock.lock();
        try {
            log.debug("hello!I am read");
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            readLock.unlock();
        }
    }

    public static void write(){
        writeLock.lock();
        try{
            log.debug("hello! I am write");
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            writeLock.unlock();
        }
    }


}
